package network

import (
	"encoding/json"
	"fmt"
	"time"

	"gitee.com/terender/sfw/rlog"
)

// Context 网络通信的上下文
type Context struct {
	conn            *Connection            // 连接对象
	msg             *Message               // 消息对象
	cache           map[string]interface{} // 数据存储区
	Time            time.Time              // 消息接收时间
	routine         Routine                // 消息处理路径
	middlewareIndex int                    // 中间件的索引, -1表示没有中间件或已经处理完，已经在消息的业务处理器过程中
	hasResonsed     bool                   // 是否已经应答了客户端
	resp            interface{}            // 消息的应答
}

// Continue 此消息上下文是否继续执行 Routine
// 在中间件中必须调用此方法，才能继续执行后续中间件以及消息处理器
// 如果在中间件中提前向客户端返回并退出时则不需要再调用此方法
// 在消息处理其中不能调用此方法
func (ctx *Context) Continue() {
	if ctx.middlewareIndex < 0 {
		rlog.Errorf(`message[%v] context.continue called after all middlewares finished`)
		return
	}
	ctx.middlewareIndex++
	if ctx.middlewareIndex < len(ctx.routine.p.middleWares) {
		ctx.routine.p.middleWares[ctx.middlewareIndex](ctx)
		return
	}
	ctx.middlewareIndex = -1
	ctx.routine.proc(ctx)
}

// Conn ...
func (ctx *Context) Conn() *Connection { return ctx.conn }

// Message ...
func (ctx *Context) Message() *Message { return ctx.msg }

// SetKV ...
func (ctx *Context) SetKV(key string, value interface{}) { ctx.cache[key] = value }

// GetKV ...
func (ctx *Context) GetKV(key string) interface{} { return ctx.cache[key] }

// ReadJSON 读取消息正文的Json数据，反序列化为结构
func (ctx *Context) ReadJSON(value interface{}) error {
	return json.Unmarshal([]byte(ctx.msg.Content), value)
}

// HasResponsed 此Context是否已经发送过应答了。一个Context只能发送一次应答
func (ctx *Context) HasResponsed() bool { return ctx.hasResonsed }

// Response 返回应答消息给客户端
func (ctx *Context) Response(value interface{}) { ctx.resp = value }

// GetResponse 获取已经写入的应答消息
func (ctx *Context) GetResponse() interface{} { return ctx.resp }

// Write 真正将应答数据发往客户端
// 将结构序列化为Json
// 应答消息的消息ID与请求消息相同
// 请求消息的ReqID被原样返回
func (ctx *Context) Write() error {
	if ctx.hasResonsed {
		err := fmt.Errorf(`Response to conn[%v]'s req[%v(%v)] duplicated`, ctx.conn.address, ctx.msg.MsgHead.ID, ctx.msg.MsgHead.ReqID)
		rlog.Errorf(`%v`, err)
		return err
	}
	msg := NewMessage(ctx.msg.MsgHead.ID, ctx.msg.MsgHead.ReqID, int32(time.Now().Unix()))

	if ctx.resp != nil {
		var err error
		msg.Content, err = json.Marshal(ctx.resp)
		if err != nil {
			rlog.Errorf(`Response to conn[%v] message[%v] json.Marshal error: %v`, ctx.conn.address, ctx.msg.MsgHead.ID, err)
			msg.Content = []byte(err.Error())
		}
		ctx.resp = nil
	} else {
		msg.Content = []byte(`{}`)
	}

	msg.MsgHead.Len = int32(len(msg.Content)) + HeadLen
	if ctx.conn.server.OnRespMessage != nil {
		ctx.conn.server.OnRespMessage(ctx, msg)
	}
	err := ctx.Conn().Write(msg)
	if err != nil {
		rlog.Errorf(`Response to conn[%v] message[%v] tcp send error: %v`, ctx.conn.address, ctx.msg.MsgHead.ID, err)
		return err
	}
	ctx.hasResonsed = true
	return err
}
